﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Xml.Serialization;
using System.IO;
using System.Text.RegularExpressions;

namespace BDSim
{
    /// <summary>
    /// 地面站类
    /// </summary>    
    [TypeConverter(typeof(PropertySorter))]    
    public class StationBase : BDSimObject
    {
        #region 字段

        private StationCollection _Parent;

        #region 气象参数
        public MeteorologicalsParam StationMeteParam = new MeteorologicalsParam();//当前时刻站点气象参数
        private MeteorologicalsParamClass _CInputMeteParam = new MeteorologicalsParamClass();   //界面输入气象参数
        private EWayToGetMeteorological _WayToGetMeteorological;
        #endregion

        #region 钟差类
        /// <summary>
        /// 卫星钟差数据（s）,间隔为钟差仿真的采样间隔（tao）
        /// </summary>
     //   [XmlIgnore]
      //  public List<ClkSimData> SatClkErrList = new List<ClkSimData>();

        /// <summary>
        /// 地面站钟差数据（s）,间隔为场景仿真步长
        /// </summary>
     //   [XmlIgnore]
      //  public List<ClkSimData> InterSatClkErrList = new List<ClkSimData>();

        /// <summary>
        /// 存储仿真钟差五步点数据数据
        /// </summary>
        [XmlIgnore]
        public List<AtomicClockErr> StaAtomicClkList = new List<AtomicClockErr>();
        /// <summary>
        /// 站实体的时间控制
        /// </summary>
        [XmlIgnore]
        public SimParam simParam ;

        /// <summary>
        /// 地面站钟类
        /// </summary>
        private StationClock _CStationClock=new StationClock ();

        #endregion 钟差类

        /// <summary>
        /// 气象环境类
        /// </summary>
        private MeteorologyMsg _CMeteorologyMsg = new MeteorologyMsg();
              
        /// <summary>
        /// 地面站类型
        /// </summary>
        private EStationType _Type;

        #region 地面站位置信息

        private ECoordinateType_ECF _StationCoordinateType = ECoordinateType_ECF.CGCS2000_BLH;
        private PosXYZClass _Pos_XYZ = new PosXYZClass();
        private PosBLHClass _Pos_BLH = new PosBLHClass();

        #endregion
                 
        #endregion

        #region 属性

        [XmlIgnore, Browsable(false)]
        public StationCollection Parent
        {
            get { return _Parent; }
            set { _Parent = value; }
        }

        [XmlAttribute, Browsable(false),ReadOnly(true)]
        public EStationType Type
        {
            get { return _Type; }
            set { _Type = value; NotifyPropertyChanged("Type"); }
        }

        #region 地面站位置信息

        /// <summary>
        /// 地面站名
        /// </summary>
        [XmlAttribute, Category("基本信息"), Description("")]
        public string Name
        {
            get { return _Name; }
            set
            {
                if (Regex.IsMatch(value, @"(?i)^[a-zA-Z0-9]+$"))
                {
                    _Name = value;
                    NotifyPropertyChanged("Name");
                }
                else
                {
                    DlgReportPropertyInfo("输入必须是英文字母加数字的格式!");
                }
            }
        }

        [DescriptionAttribute("地面站在地固坐标系中的表示类型"), CategoryAttribute("位置信息"), PropertyOrder(1)]
        public ECoordinateType_ECF CoordinateType
        {
            get { return _StationCoordinateType; }
            set
            {
                _StationCoordinateType = value;
                NodePosVel xyz_cgcs= new NodePosVel();
                NodePosVel xyz_wgs = new NodePosVel();
                BLH_PosVel blh_cgcs = new BLH_PosVel();
                BLH_PosVel blh_wgs = new BLH_PosVel();
                switch (value)   //value为选择需要转换的类型
                {
                    case ECoordinateType_ECF.CGCS2000_XYZ:  //---------------需要转换的类型
                        PropertyFieldControl.SetPropertyVisibility(this, "Pos_XYZ", true);
                        PropertyFieldControl.SetPropertyVisibility(this, "Pos_BLH", false);
                        switch (_StationCoordinateType)
	                    {
                            case ECoordinateType_ECF.CGCS2000_BLH: //原坐标类型
                                blh_cgcs.B = Pos_BLH.B;
                                blh_cgcs.L = Pos_BLH.L;
                                blh_cgcs.H = Pos_BLH.H;
                                TimeSpaceDll.BLH2XYZ(blh_cgcs, ECFtype.type_CGCS2000, out xyz_cgcs);
                                Pos_XYZ.X = xyz_cgcs.x;
                                Pos_XYZ.Y = xyz_cgcs.y;
                                Pos_XYZ.Z = xyz_cgcs.z;
                                break;

                            case ECoordinateType_ECF.WGS84_BLH: //原坐标类型
                                blh_wgs.B = Pos_BLH.B;
                                blh_wgs.L = Pos_BLH.L;
                                blh_wgs.H = Pos_BLH.H;
                                TimeSpaceDll.BLH2XYZ(blh_wgs, ECFtype.type_WGS, out xyz_wgs);
                                TimeSpaceDll.WGS2CGCS(xyz_wgs,out xyz_cgcs);
                                Pos_XYZ.X = xyz_cgcs.x;
                                Pos_XYZ.Y = xyz_cgcs.y;
                                Pos_XYZ.Z = xyz_cgcs.z;
                                break;

                            case ECoordinateType_ECF.WGS84_XYZ : //原坐标类型
                                xyz_wgs.x = Pos_XYZ.X;
                                xyz_wgs.y = Pos_XYZ.Y;
                                xyz_wgs.z = Pos_XYZ.Z;
                                TimeSpaceDll.WGS2CGCS(xyz_wgs,out xyz_cgcs);
                                Pos_XYZ.X = xyz_cgcs.x;
                                Pos_XYZ.Y = xyz_cgcs.y;
                                Pos_XYZ.Z = xyz_cgcs.z;
                                break;

                            case ECoordinateType_ECF.CGCS2000_XYZ:
                                break;		                    
	                    }
                        break;

                    case ECoordinateType_ECF.WGS84_XYZ:   //---------------需要转换的类型
                        PropertyFieldControl.SetPropertyVisibility(this, "Pos_XYZ", true);
                        PropertyFieldControl.SetPropertyVisibility(this, "Pos_BLH", false);
                        switch (_StationCoordinateType)
                        {
                            case ECoordinateType_ECF.CGCS2000_BLH: //原坐标类型
                                blh_cgcs.B = Pos_BLH.B;
                                blh_cgcs.L = Pos_BLH.L;
                                blh_cgcs.H = Pos_BLH.H;
                                TimeSpaceDll.BLH2XYZ(blh_cgcs, ECFtype.type_CGCS2000, out xyz_cgcs);
                                TimeSpaceDll.CGCS2WGS(xyz_cgcs, out xyz_wgs);
                                Pos_XYZ.X = xyz_wgs.x;
                                Pos_XYZ.Y = xyz_wgs.y;
                                Pos_XYZ.Z = xyz_wgs.z;
                                break;

                            case ECoordinateType_ECF.WGS84_BLH: //原坐标类型
                                blh_wgs.B = Pos_BLH.B;
                                blh_wgs.L = Pos_BLH.L;
                                blh_wgs.H = Pos_BLH.H;
                                TimeSpaceDll.BLH2XYZ(blh_wgs, ECFtype.type_WGS, out xyz_wgs);
                                Pos_XYZ.X = xyz_wgs.x;
                                Pos_XYZ.Y = xyz_wgs.y;
                                Pos_XYZ.Z = xyz_wgs.z;
                                break;

                            case ECoordinateType_ECF.WGS84_XYZ: //原坐标类型
                                break;

                            case ECoordinateType_ECF.CGCS2000_XYZ://原坐标类型
                                xyz_cgcs.x= Pos_XYZ.X ;
                                xyz_cgcs.y= Pos_XYZ.Y ;
                                xyz_cgcs.z= Pos_XYZ.Z ;
                                TimeSpaceDll.CGCS2WGS(xyz_cgcs, out xyz_wgs);
                                Pos_XYZ.X = xyz_wgs.x;
                                Pos_XYZ.Y = xyz_wgs.y;
                                Pos_XYZ.Z = xyz_wgs.z;
                                break;
                        }
                        break;
                    case ECoordinateType_ECF.CGCS2000_BLH:  //---------------需要转换的类型
                        PropertyFieldControl.SetPropertyVisibility(this, "Pos_XYZ", false);
                        PropertyFieldControl.SetPropertyVisibility(this, "Pos_BLH", true);
                        switch (_StationCoordinateType)
                        {
                            case ECoordinateType_ECF.CGCS2000_BLH: //原坐标类型
                                break;

                            case ECoordinateType_ECF.WGS84_BLH: //原坐标类型
                                blh_wgs.B = Pos_BLH.B;
                                blh_wgs.L = Pos_BLH.L;
                                blh_wgs.H = Pos_BLH.H;
                                TimeSpaceDll.BLH2XYZ(blh_wgs, ECFtype.type_WGS, out xyz_wgs);
                                TimeSpaceDll.WGS2CGCS(xyz_wgs, out xyz_cgcs);
                                TimeSpaceDll.XYZ2BLH(xyz_cgcs, ECFtype.type_CGCS2000, out blh_cgcs);
                                Pos_BLH.B = blh_cgcs.B;
                                Pos_BLH.L = blh_cgcs.L;
                                Pos_BLH.H = blh_cgcs.H;
                                break;

                            case ECoordinateType_ECF.WGS84_XYZ: //原坐标类型
                                xyz_wgs.x = Pos_XYZ.X;
                                xyz_wgs.y = Pos_XYZ.Y;
                                xyz_wgs.z = Pos_XYZ.Z;
                                TimeSpaceDll.WGS2CGCS(xyz_wgs, out xyz_cgcs);
                                TimeSpaceDll.XYZ2BLH(xyz_cgcs, ECFtype.type_CGCS2000, out blh_cgcs);
                                Pos_BLH.B = blh_cgcs.B;
                                Pos_BLH.L = blh_cgcs.L;
                                Pos_BLH.H = blh_cgcs.H;
                                break;

                            case ECoordinateType_ECF.CGCS2000_XYZ://原坐标类型
                                xyz_cgcs.x = Pos_XYZ.X;
                                xyz_cgcs.y = Pos_XYZ.Y;
                                xyz_cgcs.z = Pos_XYZ.Z;
                                TimeSpaceDll.XYZ2BLH(xyz_cgcs, ECFtype.type_CGCS2000, out blh_cgcs);
                                Pos_BLH.B = blh_cgcs.B;
                                Pos_BLH.L = blh_cgcs.L;
                                Pos_BLH.H = blh_cgcs.H;
                                break;
                        }
                        break;
                    case ECoordinateType_ECF.WGS84_BLH:  //---------------需要转换的类型
                        PropertyFieldControl.SetPropertyVisibility(this, "Pos_XYZ", false);
                        PropertyFieldControl.SetPropertyVisibility(this, "Pos_BLH", true);
                        switch (_StationCoordinateType)
                        {
                            case ECoordinateType_ECF.CGCS2000_BLH: //原坐标类型
                                blh_cgcs.B = Pos_BLH.B;
                                blh_cgcs.L = Pos_BLH.L;
                                blh_cgcs.H = Pos_BLH.H;
                                TimeSpaceDll.BLH2XYZ(blh_cgcs, ECFtype.type_CGCS2000, out xyz_cgcs);
                                TimeSpaceDll.CGCS2WGS(xyz_cgcs, out xyz_wgs);
                                TimeSpaceDll.XYZ2BLH(xyz_wgs, ECFtype.type_WGS, out blh_wgs);
                                Pos_BLH.B = blh_wgs.B;
                                Pos_BLH.L = blh_wgs.L;
                                Pos_BLH.H = blh_wgs.H;
                                break;

                            case ECoordinateType_ECF.WGS84_BLH: //原坐标类型
                                break;

                            case ECoordinateType_ECF.WGS84_XYZ: //原坐标类型
                                xyz_wgs.x = Pos_XYZ.X;
                                xyz_wgs.y = Pos_XYZ.Y;
                                xyz_wgs.z = Pos_XYZ.Z;
                                TimeSpaceDll.XYZ2BLH(xyz_wgs, ECFtype.type_WGS, out blh_wgs );
                                Pos_BLH.B = blh_wgs.B;
                                Pos_BLH.L = blh_wgs.L;
                                Pos_BLH.H = blh_wgs.H;
                                break;

                            case ECoordinateType_ECF.CGCS2000_XYZ://原坐标类型
                                xyz_cgcs.x = Pos_XYZ.X;
                                xyz_cgcs.y = Pos_XYZ.Y;
                                xyz_cgcs.z = Pos_XYZ.Z;
                                TimeSpaceDll.CGCS2WGS(xyz_cgcs, out xyz_wgs);
                                TimeSpaceDll.XYZ2BLH(xyz_wgs, ECFtype.type_WGS, out blh_wgs);
                                Pos_BLH.B = blh_wgs.B;
                                Pos_BLH.L = blh_wgs.L;
                                Pos_BLH.H = blh_wgs.H;
                                break;
                        }
                        break;
                }
                _StationCoordinateType = value;
                DisplayObjectProperty(this);
            }
        }

        [Browsable(false), DescriptionAttribute("地面站在地固坐标系中的直角坐标"), CategoryAttribute("位置信息"), PropertyOrder(2)]
        public PosXYZClass Pos_XYZ
        {
            get
            {
                return _Pos_XYZ;
            }
            set
            {
                _Pos_XYZ = value;
            }
        }

        [ Browsable(true), DescriptionAttribute("地面站在地固坐标系中的大地坐标"), CategoryAttribute("位置信息"), TypeConverter(typeof(PropertySorter)), PropertyOrder(3)]
        public PosBLHClass Pos_BLH
        {
            get
            {
                return _Pos_BLH;
            }
            set
            {
                _Pos_BLH = value;
            }
        }

        public StationPostion ConvertToStruct()
        {
            StationPostion newStationPostion = new StationPostion();
            newStationPostion.Type = this.CoordinateType;
            newStationPostion.Pos_XYZ.X = this.Pos_XYZ.X;
            newStationPostion.Pos_XYZ.Y = this.Pos_XYZ.Y;
            newStationPostion.Pos_XYZ.Z = this.Pos_XYZ.Z;
            newStationPostion.Pos_BLH.B = this.Pos_BLH.B;
            newStationPostion.Pos_BLH.L = this.Pos_BLH.L;
            newStationPostion.Pos_BLH.H = this.Pos_BLH.H;
            return newStationPostion;
        }

        #endregion


        #region 地面站气象信息

        /// <summary>
        /// 气象参数的获取方法，包括EGNOS模型计算、界面设置两种方式
        /// </summary>
        [XmlAttribute, DescriptionAttribute("气象参数来源控制，包括界面直接输入、文件读取两种方式"), CategoryAttribute("气象参数"), PropertyOrder(1)]
        public EWayToGetMeteorological WayToGetMeteorological
        {
            get
            {
                return _WayToGetMeteorological;
            }
            set
            {
                _WayToGetMeteorological = value;

                switch (_WayToGetMeteorological)
                {
                    case EWayToGetMeteorological.EGNOSModel:
                        PropertyFieldControl.SetPropertyVisibility(this, "CInputMeteParam", false);

                        break;
                    case EWayToGetMeteorological.用户输入:
                        PropertyFieldControl.SetPropertyVisibility(this, "CInputMeteParam", true);
                        break;
                }
                BDSimObject.DisplayObjectProperty(this);
            }
        }

        /// <summary>
        /// 气象参数
        /// </summary>
        [Browsable(false), DescriptionAttribute("气象参数，依次为"), CategoryAttribute("气象参数"), PropertyOrder(2)]
        public MeteorologicalsParamClass CInputMeteParam
        {
            get
            {
                return _CInputMeteParam;
            }
            set
            {
                _CInputMeteParam = value;
            }
        }

        #endregion

        /// <summary>
        /// 地面站钟类
        /// </summary>
        [Category("钟差信息"), Description(""),DisplayName ("钟差参数")]
        public StationClock CStationClock
        {
            get { return _CStationClock; }
            set { _CStationClock = value; }
        }

        /// <summary>
        /// 气象环境类
        /// </summary>
        [Browsable(false)]
        public MeteorologyMsg CMeteorologyMsg
        {
            get { return _CMeteorologyMsg; }
            set { _CMeteorologyMsg = value; }
        }

        #endregion        

        #region 构造函数（包含调用方法）

        #endregion

        #region 实时运行函数
        #endregion

        #region 功能一：站钟差计算实现
      
        public void ClkErrCal()
        {
            _CStationClock.Parent = this;
          //  SatClkErrList.Clear();
            StaAtomicClkList.Clear();

            //时间初始化
            simParam.pStartTime = BDSimObject.GlobalStartTime;
            simParam.simClks = 0;
            simParam.simStepInt = (int)(BDSimObject.GlobalStepSize * 1e6);

            //钟差初始化
            _CStationClock.Init();

            ///存储第一步的钟差和五步点
            StaAtomicClkList.Add(_CStationClock.StepClkErr);
            ClkSimData tempclk = new ClkSimData();
            tempclk.ClkError = _CStationClock.Clk_Err;
            tempclk.SimTime = BDSimObject.GlobalStartTime;
            //SatClkErrList.Add(tempclk);

            //钟差数据仿真（间隔为Tao）
            PreviousClkSim();

            //钟差数据插值（间隔为仿真步长）
            GenerateStepCLKErr();

            simParam.simClks = 0;

        }

        /// <summary>
        /// 中间计算函数：钟差数据仿真（间隔为Tao）
        /// </summary>
        private void PreviousClkSim()
        {
            double EndJD = BDSimObject.GlobalEndTime.JD;

            UTCTime tempTime = BDSimObject.GlobalStartTime; ;            // 把开始时间赋值给临时时间
            SimParam SimParamTemp = simParam;          //把仿真步长、节拍数、开始时间等赋值给临时仿真参数
            SimParamTemp.simStepInt = (int)(_CStationClock.Clk_tao * 1e6);

            SimParamTemp.simClks = 1;
            for (; tempTime.JD < EndJD; SimParamTemp.simClks++)
            {
                //时间仿真
                double nowTime = SimParamTemp.simClks * _CStationClock.Clk_tao;
                tempTime.IntJD = BDSimObject.GlobalStartTime.IntJD + Math.Floor(nowTime / 86400.0);
                tempTime.DouJD = BDSimObject.GlobalStartTime.DouJD + nowTime / 86400.0 - Math.Floor(nowTime / 86400.0);
                tempTime.JD = tempTime.IntJD + tempTime.DouJD;
                //钟差计算
                _CStationClock.simParam = SimParamTemp;
                _CStationClock.FixedStepOut();
                _CStationClock.RealOut(_CStationClock.StepClkErr);
                TimeSpaceDll.CAL2UTC(out tempTime, 2);

                StaAtomicClkList.Add(_CStationClock.StepClkErr);
                ClkSimData tempclk = new ClkSimData();
                tempclk.ClkError = _CStationClock.Clk_Err;
                tempclk.SimTime = tempTime;
                //SatClkErrList.Add(tempclk);
            }

        }

        /// <summary>
        /// 产生指定步长的钟差数据，默认步长为系统仿真步长
        /// </summary>
        /// <param name="simStep">仿真步长，单位s</param>
        /// <returns></returns>
        public List<ClkSimData> GenerateStepCLKErr(double simStep = 0)
        {
            List<ClkSimData> clkErrList = new List<ClkSimData>();
            try
            {
                if (BDSimObject.GlobalStatus != ESimStatus.UnInited && BDSimObject.GlobalStatus != ESimStatus.Run && StaAtomicClkList != null && StaAtomicClkList.Count != 0)
                {
                    simParam.simStepInt = (int)(BDSimObject.GlobalStepSize * 1e6);
                    SimParam tempSimParam = simParam;
                    //当用户设定了大于0的自定义步长时，即使用
                    if (simStep > 0)
                    {
                        tempSimParam.simStepInt = (int)(simStep * 1000000);
                    }
                    tempSimParam.simClks = 0;
                    DateTime simTime = BDSimObject.GlobalStartTime.ToDateTime();
                    while (true)
                    {
                        int clkListID = (int)Math.Floor((tempSimParam.simClks * (tempSimParam.simStepInt * 1e-6)) / CStationClock.Clk_tao);
                        CStationClock.simParam = tempSimParam;//更新轨道模块实时时间 
                        CStationClock.RealOut(StaAtomicClkList[clkListID]);
                        ClkSimData tempData = new ClkSimData() { ID = this.Id, Name = this.Name, ClkError = CStationClock.Clk_Err, SimTime = new UTCTime(simTime.Year, simTime.Month, simTime.Day, simTime.Hour, simTime.Minute, simTime.Second, 0) };
                        TimeSpaceDll.CAL2UTC(out tempData.SimTime, 1);
                        clkErrList.Add(tempData);
                        if (clkListID >= StaAtomicClkList.Count() - 1)//如果超出了LIST存储的时间范围，则返回
                        {
                            break;
                        }
                        simTime = simTime.AddSeconds(tempSimParam.simStepInt * 1e-6);
                        tempSimParam.simClks++;
                    }
                }
            }
            catch (Exception)
            {

            }
            return clkErrList;
        }

        /// <summary>
        /// 实时计算地面站钟差
        /// </summary>
        /// <param name="CurTime"></param>
        /// <returns></returns>
        public double RealTimeClkErr(UTCTime CurTime)
        {
            double ClkErr = 0;
            TimeSpaceDll.CAL2UTC(out CurTime, 1);
            double nowTime = (CurTime.JD - GlobalStartTime.JD) * 86400 + 0.0001;
            int TimeId = 0;
            TimeId = (int)Math.Floor(nowTime / CStationClock.Clk_tao);
            AtomicClockErr AtoClk = StaAtomicClkList[TimeId];
            //实时计算钟差
            ClkTrp_Input clkTrp_Input;
            ClkTrp_Param clkTrp_Param;
            ClkTrp_Output clkTrp_Output;
            clkTrp_Input.tobs = nowTime;
            clkTrp_Input.a = new double[7];
            clkTrp_Input.a[0] = TimeId;
            clkTrp_Input.a[1] = CStationClock.Clk_tao;
            clkTrp_Input.a[2] = AtoClk.m_sb2;
            clkTrp_Input.a[3] = AtoClk.m_sb1;
            clkTrp_Input.a[4] = AtoClk.m_s0;
            clkTrp_Input.a[5] = AtoClk.m_sa1;
            clkTrp_Input.a[6] = AtoClk.m_sa2;
            clkTrp_Param.Iclo = 1;
            CClkSimDLL.ClockErr_Trp(clkTrp_Input, clkTrp_Param, out clkTrp_Output);
            ClkErr = clkTrp_Output.DeltClock;//实时计算钟差

            return ClkErr;
        }

        #endregion

        #region 功能二：气象参数计算

        public void GetMeteorological(UTCTime CurTime )
        {
            CMeteorologyMsg.Parent = this;
            if (WayToGetMeteorological == EWayToGetMeteorological.EGNOSModel)
            {
                CMeteorologyMsg.GetMeteorological(CurTime,ConvertToStruct().Pos_BLH);
                StationMeteParam = CMeteorologyMsg.MetParamMsg;
            }
            else
            {
                StationMeteParam = CInputMeteParam.ToStruct();
            } 
        }

        #endregion


        internal void Remove(SendReceiveDeviceDataProvider sendReceiveDeviceDataProvider)
        {
            throw new NotImplementedException();
        }
    }
}
